package net.ib.mtalk.network.task;

import net.ib.mtalk.network.NetResultReceiver;
import net.ib.mtalk.network.NetResultReceiver.Receiver;
import net.ib.mtalk.network.TcpClient;
import net.ib.mtalk.network.TcpEnvelope;
import net.ib.mtalk.network.task.NetTaskHandler.MyHandler;
import net.ib.mtalk.util.MTalkLogWriter;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 * ServerAPI을 호출하려면 이 Class를 구현하도록 한다.<br>
 * NetTaskHandler에 AsyncNetTask를 이용하여 ThreadHandler에 queueing할 수 있다.<br>
 * 요청 전에 할 일은 onPreExecute()에 지정하고<br> 
 * 결과를 받은 후 onPostExecute() 함수를 호출해 주므로<br>
 * 다시 MainThread로 돌아오지 않고, workThread에서 Task의 일련된 작업을 COMBINED Login을 구현할 수 있다.
 * @author eugenel
 * @see net.ib.mtalk.network.task.NetTaskHandler
 *
 */
public abstract class AsyncNetTask {
	
	protected TcpEnvelope mEnvelope;
	protected MyHandler myHandler;
	protected Handler mUiHandler;
	protected Context mContext;
	
	public AsyncNetTask(Context context){
		this.mContext = context;
		this.myHandler = (MyHandler) NetTaskHandler.getInstance().getHandler();
	} 
	
	/**
	 * 
	 * @param _context
	 * @param _uiHandler : 결과가 끝나고 다시 UI로 돌아올 Handler
	 */
	public AsyncNetTask(Context context, Handler uiHandler){
		this.mContext = context;
		this.mUiHandler = uiHandler;
		this.myHandler = (MyHandler) NetTaskHandler.getInstance().getHandler();
	}
	
	/**
	 * onPreExecute()함수는 전송 전, Database 등 작업 후,
	 * Envelope을 만드는 용도로 사용된다
	 * TCP Call 작업이 없으면 null을 리턴한다
	 * @return - TcpEvelope(nullable)
	 */
	protected abstract TcpEnvelope onPreExecute();
	
	/**
	 * TCP작업 후 또는, onPreExecute() 후에 호출되는 함수
	 * @param resultCode
	 * @param sentObject
	 * @param receivedObject
	 */
	protected abstract void onPostExecute(int resultCode, Object sentObject, Object receivedObject);
	
	protected void onWorkRequeated(AsyncNetTask asyncTask){
		TcpEnvelope obj = onPreExecute();
		_onWorkRequeated(obj);
	}
	
	protected void _onWorkRequeated(TcpEnvelope obj) {
		if (obj == null) {	// 네트워크 요청이 없이 바로 다음 단계로 넘어가는 경우.
			onPostExecute(NetResultReceiver.NONE, null, null);
			return;
		}
		this.mEnvelope = obj;
		Task task = new Task(this.mEnvelope);
		NetResultReceiver receiver = new NetResultReceiver(myHandler, (Receiver)task);
		mEnvelope.setCallback(receiver);
		task.execute();
	}
	
	public void execute() {
		Message msg = new Message();
		msg.obj = this;
		myHandler.sendMessage(msg);
	}
		
	class Task implements Receiver {
		
		private TcpEnvelope mEnvelope;
		
		public Task(TcpEnvelope envelope){
			mEnvelope = envelope;
		}
		
		public void execute(){
			if(mEnvelope!=null){
				TcpClient.send(mEnvelope);
			} else {
				// If envelope is null, go onNetResult() directly
				onNetResult(0, null, null);
			}
		}

		@Override
		public void onNetResult(int resultCode, Object sentObject, Object receivedObject) {
			MTalkLogWriter.v("AsyncNetTask.Task.onNetResult()");
			onPostExecute(resultCode, sentObject, receivedObject);
		}

		@Override
		public void onNetError(int resultCode, Object sentObject) {
			MTalkLogWriter.v("AsyncNetTask.Task.onNetError()");
			onPostExecute(resultCode, sentObject, null);
		}
	}
}
